﻿/*
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
 *
 * This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
 *
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
 */

#include <arpa/inet.h>
#include "MediaSource.h"
#include "Util/util.h"
#include "config.h"
#include "Parser.h"


namespace toolkit {

	/////////////////////////////////////MediaInfo//////////////////////////////////////

	void MediaInfo::parse(const string &url_in) {
		_full_url = url_in;
		string url = url_in;
		auto pos = url.find("?");
		if (pos != string::npos) {
			_param_strs = url.substr(pos + 1);
			url.erase(pos);
		}

		auto schema_pos = url.find("://");
		if (schema_pos != string::npos) {
			_schema = url.substr(0, schema_pos);
		}
		else {
			schema_pos = -3;
		}
		auto split_vec = split(url.substr(schema_pos + 3), "/");
		if (split_vec.size() > 0) {
			auto vhost = split_vec[0];
			auto pos = vhost.find(":");
			if (pos != string::npos) {
				_host = _vhost = vhost.substr(0, pos);
				_port = vhost.substr(pos + 1);
			}
			else {
				_host = _vhost = vhost;
			}
			if (_vhost == "localhost" || INADDR_NONE != inet_addr(_vhost.data())) {
				//如果访问的是localhost或ip，那么则为默认虚拟主机
				_vhost = DEFAULT_VHOST;
			}
		}
		if (split_vec.size() > 1) {
			_app = split_vec[1];
		}
		if (split_vec.size() > 2) {
			string stream_id;
			for (size_t i = 2; i < split_vec.size(); ++i) {
				stream_id.append(split_vec[i] + "/");
			}
			if (stream_id.back() == '/') {
				stream_id.pop_back();
			}
			_streamid = stream_id;
		}

		auto params = Parser::parseArgs(_param_strs);
		if (params.find(VHOST_KEY) != params.end()) {
			_vhost = params[VHOST_KEY];
		}

		GET_CONFIG(bool, enableVhost, General::kEnableVhost);
		if (!enableVhost || _vhost.empty()) {
			//如果关闭虚拟主机或者虚拟主机为空，则设置虚拟主机为默认
			_vhost = DEFAULT_VHOST;
		}
	}

	/////////////////////////////////////FlushPolicy//////////////////////////////////////

	static bool isFlushAble_default(bool is_video, uint64_t last_stamp, uint64_t new_stamp, size_t cache_size) {
		if (new_stamp + 500 < last_stamp) {
			//时间戳回退比较大(可能seek中)，由于rtp中时间戳是pts，是可能存在一定程度的回退的
			return true;
		}

		//时间戳发送变化或者缓存超过1024个,sendmsg接口一般最多只能发送1024个数据包
		return last_stamp != new_stamp || cache_size >= 1024;
	}

	static bool isFlushAble_merge(bool is_video, uint64_t last_stamp, uint64_t new_stamp, size_t cache_size, int merge_ms) {
		if (new_stamp + 500 < last_stamp) {
			//时间戳回退比较大(可能seek中)，由于rtp中时间戳是pts，是可能存在一定程度的回退的
			return true;
		}

		if (new_stamp > last_stamp + merge_ms) {
			//时间戳增量超过合并写阈值
			return true;
		}

		//缓存数超过1024个,这个逻辑用于避免时间戳异常的流导致的内存暴增问题
		//而且sendmsg接口一般最多只能发送1024个数据包
		return cache_size >= 1024;
	}

	bool FlushPolicy::isFlushAble(bool is_video, bool is_key, uint64_t new_stamp, size_t cache_size) {
		bool flush_flag = false;
		if (is_key && is_video) {
			//遇到关键帧flush掉前面的数据，确保关键帧为该组数据的第一帧，确保GOP缓存有效
			flush_flag = true;
		}
		else {
			GET_CONFIG(int, mergeWriteMS, General::kMergeWriteMS);
			if (mergeWriteMS <= 0) {
				//关闭了合并写或者合并写阈值小于等于0
				flush_flag = isFlushAble_default(is_video, _last_stamp[is_video], new_stamp, cache_size);
			}
			else {
				flush_flag = isFlushAble_merge(is_video, _last_stamp[is_video], new_stamp, cache_size, mergeWriteMS);
			}
		}

		if (flush_flag) {
			_last_stamp[is_video] = new_stamp;
		}
		return flush_flag;
	}

} /* namespace toolkit */